import 'dart:async';

import 'package:aero_frisbee/app/model/af_user_info_model/af_user_info_model.dart';
import 'package:aero_frisbee/app/req/af_req_api.dart';
import 'package:aero_frisbee/app/state/app_cache_state.dart';
import 'package:aero_frisbee/pages/modues/message/pages/message/view_model/af_conversation_list_view_model.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart';

part 'af_message_detail_view_model.g.dart';

@Riverpod(keepAlive: true)
FutureOr<AfUserInfoModel> getUserInfoFuture(GetUserInfoFutureRef ref,
    {required String userId}) {
  final api = ref.watch(appApiProvider);
  return api.fetchUserInfo(userId: userId);
}

@riverpod
class AfMessageDetailListService extends _$AfMessageDetailListService {
  @override
  FutureOr<List<RCIMIWMessage>> build({required String userId}) {
    final engine = ref.read(curEngineProvider);
    ref.onDispose(() {
      engine?.onMessageReceived == null;
    });

    engine?.onMessageReceived =
        (RCIMIWMessage? message, int? left, bool? offline, bool? hasPackage) {
      if (message?.conversationType == RCIMIWConversationType.private) {
        appendMessage(
          [message!],
          front: true,
        );
      }
    };
    return getMessages(0);
  }

  List<RCIMIWMessage> get _currentData {
    final current = state.maybeWhen(
        data: ((data) => data), orElse: (() => List<RCIMIWMessage>.from([])));
    return current;
  }

  void appendMessage(List<RCIMIWMessage> messages, {bool front = false}) {
    state = AsyncData(
      List<RCIMIWMessage>.from(
        [
          if (front) ...messages,
          ..._currentData,
          if (!front) ...messages,
        ],
      ),
    );
  }

  Future<List<RCIMIWMessage>> getMessages(int mostOldMessageTime) async {
    final completer = Completer<List<RCIMIWMessage>>();
    var count = 20;
    final engine = ref.read(curEngineProvider);
    await engine?.clearUnreadCount(RCIMIWConversationType.private, userId, null,
        DateTime.now().millisecondsSinceEpoch);

    ref.invalidate(afConversationListServiceProvider);
    engine?.getMessages(
      RCIMIWConversationType.private,
      userId,
      null,
      mostOldMessageTime,
      RCIMIWTimeOrder.before,
      RCIMIWMessageOperationPolicy.remote,
      count,
      callback: IRCIMIWGetMessagesCallback(onSuccess: (v) {
        completer.complete(v);
      }, onError: (c) {
        completer.completeError('fetch data list error');
      }),
    );
    return completer.future;
  }

  void sendTextMessage(String text) async {
    final engine = ref.read(curEngineProvider);
    var message = await engine!.createTextMessage(
      RCIMIWConversationType.private,
      userId,
      null,
      text,
    );
    if (message != null) {
      _sendMessage(message);
    }
  }

  void sendImageMessage(String imgPath) async {
    final engine = ref.read(curEngineProvider);
    var message = await engine!.createImageMessage(
      RCIMIWConversationType.private,
      userId,
      null,
      imgPath,
    );
    if (message != null) {
      _sendMessage(message);
    }
  }

  void sendFileMessage(String filePath) async {
    final engine = ref.read(curEngineProvider);
    var message = await engine!.createFileMessage(
      RCIMIWConversationType.private,
      userId,
      null,
      filePath,
    );
    if (message != null) {
      _sendMessage(message);
    }
  }

  void sendVoiceMessage({required String path, required int duration}) async {
    final engine = ref.read(curEngineProvider);
    var message = await engine!.createVoiceMessage(
      RCIMIWConversationType.private,
      userId,
      null,
      path,
      duration,
    );
    if (message != null) {
      _sendMessage(message);
    }
  }

  _sendMessage(RCIMIWMessage message) {
    final engine = ref.read(curEngineProvider);
    if (message is RCIMIWMediaMessage) {
      engine?.sendMediaMessage(
        message,
        listener: RCIMIWSendMediaMessageListener(
          onMediaMessageSent: (int? code, RCIMIWMediaMessage? message) {
            if (message != null) {
              appendMessage([message], front: true);
            }
          },
        ),
      );
    } else {
      engine?.sendMessage(
        message,
        callback: RCIMIWSendMessageCallback(
          onMessageSaved: (message) {
            if (message != null) {
              appendMessage([message], front: true);
            }
          },
          onMessageSent: (ret, message) {},
        ),
      );
    }
  }
}
